package net.starwifi.duobao.entity;

import com.fasterxml.jackson.annotation.JsonProperty;
import freemarker.template.TemplateException;
import net.starwifi.duobao.utils.FreemarkerUtils;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;

import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.Digits;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

/**
 *
 * 精选产品
 * Created by Administrator on 2015/9/28.
 */
@Entity
@Table(name = "duob_product")
@SequenceGenerator(name = "sequenceGenerator", sequenceName = "duob_product_sequence")
public class Product extends BaseEntity {

    private static final long serialVersionUID = 2167830430439593293L;

    /** 点击数缓存名称 */
    public static final String HITS_CACHE_NAME = "productHits";

    /** 点击数缓存更新间隔时间 */
    public static final int HITS_CACHE_INTERVAL = 600000;

    /** 商品属性值属性个数 */
    public static final int ATTRIBUTE_VALUE_PROPERTY_COUNT = 20;

    /** 商品属性值属性名称前缀 */
    public static final String ATTRIBUTE_VALUE_PROPERTY_NAME_PREFIX = "attributeValue";

    /** 全称规格前缀 */
    public static final String FULL_NAME_SPECIFICATION_PREFIX = "[";

    /** 全称规格后缀 */
    public static final String FULL_NAME_SPECIFICATION_SUFFIX = "]";

    /** 全称规格分隔符 */
    public static final String FULL_NAME_SPECIFICATION_SEPARATOR = " ";

   /* static {
        try {
            File xmlFile = new ClassPathResource(SettingUtils.configPath).getFile();
            org.dom4j.Document document = new SAXReader().read(xmlFile);
            org.dom4j.Element element = (org.dom4j.Element) document.selectSingleNode("/app/template[@id='productContent']");
            staticPath = element.attributeValue("staticPath");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }*/

    /** 静态路径 */
    private static String staticPath;

    /** 编号 */
    private String sn;

    /** 名称 */
    private String name;

    /** 全称 */
    private String fullName;

    /** 销售价 */
    private BigDecimal price;

    /** 成本价 */
    private BigDecimal cost;

    /** 市场价 */
    private BigDecimal marketPrice;

    /** 展示图片 */
    private String image;

    /** 单位 */
    private String unit;

    /** 重量 */
    private Integer weight;

    /** 库存 */
    private Integer stock;

    /** 已分配库存 */
    private Integer allocatedStock;

    /** 库存备注 */
    private String stockMemo;

    /** 赠送积分 */
    private Long point;

    /** 是否上架 */
    private Boolean isMarketable;

    /** 是否列出 */
    private Boolean isList;

    /** 是否置顶 */
    private Boolean isTop;

    /** 是否为赠品 */
    private Boolean isGift;

    /** 介绍 */
    private String introduction;

    /** 备注 */
    private String memo;

    /** 搜索关键词 */
    private String keyword;

    /** 页面标题 */
    private String seoTitle;

    /** 页面关键词 */
    private String seoKeywords;

    /** 页面描述 */
    private String seoDescription;

    /** 评分 */
    private Float score;

    /** 总评分 */
    private Long totalScore;

    /** 评分数 */
    private Long scoreCount;

    /** 点击数 */
    private Long hits;

    /** 周点击数 */
    private Long weekHits;

    /** 月点击数 */
    private Long monthHits;

    /** 销量 */
    private Long sales;

    /** 周销量 */
    private Long weekSales;

    /** 月销量 */
    private Long monthSales;

    /** 周点击数更新日期 */
    private Date weekHitsDate;

    /** 月点击数更新日期 */
    private Date monthHitsDate;

    /** 周销量更新日期 */
    private Date weekSalesDate;

    /** 月销量更新日期 */
    private Date monthSalesDate;

    /** 商品分类 */
    private ProductCategory productCategory;

    /** 商品图片 */
    private List<ProductImage> productImages = new ArrayList<ProductImage>();

    /** 评论 */
    private Set<Review> reviews = new HashSet<Review>();

    /** 咨询 */
    private Set<Consultation> consultations = new HashSet<Consultation>();

    /** 商家ID */
    private Long shopId;

    /** 店铺名称 */
    private String shopName;

    /**
     * 获取编号
     *
     * @return 编号
     */
    @JsonProperty
    @Pattern(regexp = "^[0-9a-zA-Z_-]+$")
    @Length(max = 100)
    @Column(nullable = false, unique = true, length = 100)
    public String getSn() {
        return sn;
    }

    /**
     * 设置编号
     *
     * @param sn
     *            编号
     */
    public void setSn(String sn) {
        this.sn = sn;
    }

    /**
     * 获取名称
     *
     * @return 名称
     */
    @JsonProperty
    @NotEmpty
    @Length(max = 200)
    @Column(nullable = false)
    public String getName() {
        return name;
    }

    /**
     * 设置名称
     *
     * @param name
     *            名称
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取全称
     *
     * @return 全称
     */
    @JsonProperty
    @Column(nullable = false)
    public String getFullName() {
        return fullName;
    }

    /**
     * 设置全称
     *
     * @param fullName
     *            全称
     */
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    /**
     * 获取销售价
     *
     * @return 销售价
     */
    @JsonProperty
    @NotNull
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(nullable = false, precision = 21, scale = 6)
    public BigDecimal getPrice() {
        return price;
    }

    /**
     * 设置销售价
     *
     * @param price
     *            销售价
     */
    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    /**
     * 获取成本价
     *
     * @return 成本价
     */
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(precision = 21, scale = 6)
    public BigDecimal getCost() {
        return cost;
    }

    /**
     * 设置成本价
     *
     * @param cost
     *            成本价
     */
    public void setCost(BigDecimal cost) {
        this.cost = cost;
    }

    /**
     * 获取市场价
     *
     * @return 市场价
     */
    @Min(0)
    @Digits(integer = 12, fraction = 3)
    @Column(nullable = false, precision = 21, scale = 6)
    public BigDecimal getMarketPrice() {
        return marketPrice;
    }

    /**
     * 设置市场价
     *
     * @param marketPrice
     *            市场价
     */
    public void setMarketPrice(BigDecimal marketPrice) {
        this.marketPrice = marketPrice;
    }

    /**
     * 获取展示图片
     *
     * @return 展示图片
     */
    @JsonProperty
    @Length(max = 200)
    public String getImage() {
        return image;
    }

    /**
     * 设置展示图片
     *
     * @param image
     *            展示图片
     */
    public void setImage(String image) {
        this.image = image;
    }

    /**
     * 获取单位
     *
     * @return 单位
     */
    @JsonProperty
    @Length(max = 200)
    public String getUnit() {
        return unit;
    }

    /**
     * 设置单位
     *
     * @param unit
     *            单位
     */
    public void setUnit(String unit) {
        this.unit = unit;
    }

    /**
     * 获取重量
     *
     * @return 重量
     */
    @Min(0)
    public Integer getWeight() {
        return weight;
    }

    /**
     * 设置重量
     *
     * @param weight
     *            重量
     */
    public void setWeight(Integer weight) {
        this.weight = weight;
    }

    /**
     * 获取库存
     *
     * @return 库存
     */
    @Min(0)
    public Integer getStock() {
        return stock;
    }

    /**
     * 设置库存
     *
     * @param stock
     *            库存
     */
    public void setStock(Integer stock) {
        this.stock = stock;
    }

    /**
     * 获取已分配库存
     *
     * @return 已分配库存
     */
    @Column(nullable = false)
    public Integer getAllocatedStock() {
        return allocatedStock;
    }

    /**
     * 设置已分配库存
     *
     * @param allocatedStock
     *            已分配库存
     */
    public void setAllocatedStock(Integer allocatedStock) {
        this.allocatedStock = allocatedStock;
    }

    /**
     * 获取库存备注
     *
     * @return 库存备注
     */
    @Length(max = 200)
    public String getStockMemo() {
        return stockMemo;
    }

    /**
     * 设置库存备注
     *
     * @param stockMemo
     *            库存备注
     */
    public void setStockMemo(String stockMemo) {
        this.stockMemo = stockMemo;
    }

    /**
     * 获取赠送积分
     *
     * @return 赠送积分
     */
    @Min(0)
    @Column
    public Long getPoint() {
        return point;
    }

    /**
     * 设置赠送积分
     *
     * @param point
     *            赠送积分
     */
    public void setPoint(Long point) {
        this.point = point;
    }

    /**
     * 获取是否上架
     *
     * @return 是否上架
     */
    @NotNull
    @Column(nullable = false)
    public Boolean getIsMarketable() {
        return isMarketable;
    }

    /**
     * 设置是否上架
     *
     * @param isMarketable
     *            是否上架
     */
    public void setIsMarketable(Boolean isMarketable) {
        this.isMarketable = isMarketable;
    }

    /**
     * 获取是否列出
     *
     * @return 是否列出
     */
    @NotNull
    @Column(nullable = false)
    public Boolean getIsList() {
        return isList;
    }

    /**
     * 设置是否列出
     *
     * @param isList
     *            是否列出
     */
    public void setIsList(Boolean isList) {
        this.isList = isList;
    }

    /**
     * 获取是否置顶
     *
     * @return 是否置顶
     */
    @NotNull
    @Column(nullable = false)
    public Boolean getIsTop() {
        return isTop;
    }

    /**
     * 设置是否置顶
     *
     * @param isTop
     *            是否置顶
     */
    public void setIsTop(Boolean isTop) {
        this.isTop = isTop;
    }

    /**
     * 获取是否为赠品
     *
     * @return 是否为赠品
     */
    @JsonProperty
    //@NotNull
    @Column(nullable = false)
    public Boolean getIsGift() {
        return isGift;
    }

    /**
     * 设置是否为赠品
     *
     * @param isGift
     *            是否为赠品
     */
    public void setIsGift(Boolean isGift) {
        this.isGift = isGift;
    }

    /**
     * 获取介绍
     *
     * @return 介绍
     */
    @Lob
    public String getIntroduction() {
        return introduction;
    }

    /**
     * 设置介绍
     *
     * @param introduction
     *            介绍
     */
    public void setIntroduction(String introduction) {
        this.introduction = introduction;
    }

    /**
     * 获取备注
     *
     * @return 备注
     */
    @Length(max = 200)
    public String getMemo() {
        return memo;
    }

    /**
     * 设置备注
     *
     * @param memo
     *            备注
     */
    public void setMemo(String memo) {
        this.memo = memo;
    }

    /**
     * 获取搜索关键词
     *
     * @return 搜索关键词
     */
    @Length(max = 200)
    public String getKeyword() {
        return keyword;
    }

    /**
     * 设置搜索关键词
     *
     * @param keyword
     *            搜索关键词
     */
    public void setKeyword(String keyword) {
        if (keyword != null) {
            keyword = keyword.replaceAll("[,\\s]*,[,\\s]*", ",").replaceAll("^,|,$", "");
        }
        this.keyword = keyword;
    }

    /**
     * 获取页面标题
     *
     * @return 页面标题
     */
    @Length(max = 200)
    public String getSeoTitle() {
        return seoTitle;
    }

    /**
     * 设置页面标题
     *
     * @param seoTitle
     *            页面标题
     */
    public void setSeoTitle(String seoTitle) {
        this.seoTitle = seoTitle;
    }

    /**
     * 获取页面关键词
     *
     * @return 页面关键词
     */
    @Length(max = 200)
    public String getSeoKeywords() {
        return seoKeywords;
    }

    /**
     * 设置页面关键词
     *
     * @param seoKeywords
     *            页面关键词
     */
    public void setSeoKeywords(String seoKeywords) {
        if (seoKeywords != null) {
            seoKeywords = seoKeywords.replaceAll("[,\\s]*,[,\\s]*", ",").replaceAll("^,|,$", "");
        }
        this.seoKeywords = seoKeywords;
    }

    /**
     * 获取页面描述
     *
     * @return 页面描述
     */
    @Length(max = 200)
    public String getSeoDescription() {
        return seoDescription;
    }

    /**
     * 设置页面描述
     *
     * @param seoDescription
     *            页面描述
     */
    public void setSeoDescription(String seoDescription) {
        this.seoDescription = seoDescription;
    }

    /**
     * 获取评分
     *
     * @return 评分
     */
    @Column(nullable = false, precision = 12, scale = 6)
    public Float getScore() {
        return score;
    }

    /**
     * 设置评分
     *
     * @param score
     *            评分
     */
    public void setScore(Float score) {
        this.score = score;
    }

    /**
     * 获取总评分
     *
     * @return 总评分
     */
    @Column(nullable = false)
    public Long getTotalScore() {
        return totalScore;
    }

    /**
     * 设置总评分
     *
     * @param totalScore
     *            总评分
     */
    public void setTotalScore(Long totalScore) {
        this.totalScore = totalScore;
    }

    /**
     * 获取评分数
     *
     * @return 评分数
     */
    @Column(nullable = false)
    public Long getScoreCount() {
        return scoreCount;
    }

    /**
     * 设置评分数
     *
     * @param scoreCount
     *            评分数
     */
    public void setScoreCount(Long scoreCount) {
        this.scoreCount = scoreCount;
    }

    /**
     * 获取点击数
     *
     * @return 点击数
     */
    @Column(nullable = false)
    public Long getHits() {
        return hits;
    }

    /**
     * 设置点击数
     *
     * @param hits
     *            点击数
     */
    public void setHits(Long hits) {
        this.hits = hits;
    }

    /**
     * 获取周点击数
     *
     * @return 周点击数
     */
    @Column(nullable = false)
    public Long getWeekHits() {
        return weekHits;
    }

    /**
     * 设置周点击数
     *
     * @param weekHits
     *            周点击数
     */
    public void setWeekHits(Long weekHits) {
        this.weekHits = weekHits;
    }

    /**
     * 获取月点击数
     *
     * @return 月点击数
     */
    @Column(nullable = false)
    public Long getMonthHits() {
        return monthHits;
    }

    /**
     * 设置月点击数
     *
     * @param monthHits
     *            月点击数
     */
    public void setMonthHits(Long monthHits) {
        this.monthHits = monthHits;
    }

    /**
     * 获取销量
     *
     * @return 销量
     */
    @Column(nullable = false)
    public Long getSales() {
        return sales;
    }

    /**
     * 设置销量
     *
     * @param sales
     *            销量
     */
    public void setSales(Long sales) {
        this.sales = sales;
    }

    /**
     * 获取周销量
     *
     * @return 周销量
     */
    @Column(nullable = false)
    public Long getWeekSales() {
        return weekSales;
    }

    /**
     * 设置周销量
     *
     * @param weekSales
     *            周销量
     */
    public void setWeekSales(Long weekSales) {
        this.weekSales = weekSales;
    }

    /**
     * 获取月销量
     *
     * @return 月销量
     */
    @Column(nullable = false)
    public Long getMonthSales() {
        return monthSales;
    }

    /**
     * 设置月销量
     *
     * @param monthSales
     *            月销量
     */
    public void setMonthSales(Long monthSales) {
        this.monthSales = monthSales;
    }

    /**
     * 获取周点击数更新日期
     *
     * @return 周点击数更新日期
     */
    @Column(nullable = false)
    public Date getWeekHitsDate() {
        return weekHitsDate;
    }

    /**
     * 设置周点击数更新日期
     *
     * @param weekHitsDate
     *            周点击数更新日期
     */
    public void setWeekHitsDate(Date weekHitsDate) {
        this.weekHitsDate = weekHitsDate;
    }

    /**
     * 获取月点击数更新日期
     *
     * @return 月点击数更新日期
     */
    @Column(nullable = false)
    public Date getMonthHitsDate() {
        return monthHitsDate;
    }

    /**
     * 设置月点击数更新日期
     *
     * @param monthHitsDate
     *            月点击数更新日期
     */
    public void setMonthHitsDate(Date monthHitsDate) {
        this.monthHitsDate = monthHitsDate;
    }

    /**
     * 获取周销量更新日期
     *
     * @return 周销量更新日期
     */
    @Column(nullable = false)
    public Date getWeekSalesDate() {
        return weekSalesDate;
    }

    /**
     * 设置周销量更新日期
     *
     * @param weekSalesDate
     *            周销量更新日期
     */
    public void setWeekSalesDate(Date weekSalesDate) {
        this.weekSalesDate = weekSalesDate;
    }

    /**
     * 获取月销量更新日期
     *
     * @return 月销量更新日期
     */
    @Column(nullable = false)
    public Date getMonthSalesDate() {
        return monthSalesDate;
    }

    /**
     * 设置月销量更新日期
     *
     * @param monthSalesDate
     *            月销量更新日期
     */
    public void setMonthSalesDate(Date monthSalesDate) {
        this.monthSalesDate = monthSalesDate;
    }


    /**
     * 获取商品分类
     *
     * @return 商品分类
     */
    //@NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(nullable = false)
    public ProductCategory getProductCategory() {
        return productCategory;
    }

    /**
     * 设置商品分类
     *
     * @param productCategory
     *            商品分类
     */
    public void setProductCategory(ProductCategory productCategory) {
        this.productCategory = productCategory;
    }


    /**
     * 获取商品图片
     *
     * @return 商品图片
     */
    @Valid
    @ElementCollection(fetch = FetchType.EAGER)
    @CollectionTable(name = "duob_product_product_image")
    public List<ProductImage> getProductImages() {
        return productImages;
    }

    /**
     * 设置商品图片
     *
     * @param productImages
     *            商品图片
     */
    public void setProductImages(List<ProductImage> productImages) {
        this.productImages = productImages;
    }

    /**
     * 获取评论
     *
     * @return 评论
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<Review> getReviews() {
        return reviews;
    }

    /**
     * 设置评论
     *
     * @param reviews
     *            评论
     */
    public void setReviews(Set<Review> reviews) {
        this.reviews = reviews;
    }

    /**
     * 获取咨询
     *
     * @return 咨询
     */
    @OneToMany(mappedBy = "product", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
    public Set<Consultation> getConsultations() {
        return consultations;
    }

    /**
     * 设置咨询
     *
     * @param consultations
     *            咨询
     */
    public void setConsultations(Set<Consultation> consultations) {
        this.consultations = consultations;
    }

    @Column
    @JoinColumn(name = "shop_id")
    public Long getShopId() {
        return shopId;
    }

    public void setShopId(Long shopId) {
        this.shopId = shopId;
    }

    @Column
    @JoinColumn(name = "shop_name")
    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    /**
     * 获取访问路径
     *
     * @return 访问路径
     */
    @JsonProperty
    @Transient
    public String getPath() {
        Map<String, Object> model = new HashMap<String, Object>();
        model.put("id", getId());
        model.put("createDate", getCreateDate());
        model.put("modifyDate", getModifyDate());
        model.put("sn", getSn());
        model.put("name", getName());
        model.put("fullName", getFullName());
        model.put("seoTitle", getSeoTitle());
        model.put("seoKeywords", getSeoKeywords());
        model.put("seoDescription", getSeoDescription());
        model.put("productCategory", getProductCategory());
        try {
            return FreemarkerUtils.process(staticPath, model);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取缩略图
     *
     * @return 缩略图
     */
    @JsonProperty
    @Transient
    public String getThumbnail() {
        if (getProductImages() != null && !getProductImages().isEmpty()) {
            return getProductImages().get(0).getThumbnail();
        }
        return null;
    }

    /**
     * 获取缩略图
     *
     * @return 缩略图
     */
    @JsonProperty
    @Transient
    public String getMedium() {
        if (getProductImages() != null && !getProductImages().isEmpty()) {
            return getProductImages().get(0).getMedium();
        }
        return null;
    }

    /**
     * 获取缩略图
     *
     * @return 缩略图
     */
    @JsonProperty
    @Transient
    public String getLarge() {
        if (getProductImages() != null && !getProductImages().isEmpty()) {
            return getProductImages().get(0).getLarge();
        }
        return null;
    }
    /**
     * 获取可用库存
     *
     * @return 可用库存
     */
    @Transient
    public Integer getAvailableStock() {
        Integer availableStock = null;
        if (getStock() != null && getAllocatedStock() != null) {
            availableStock = getStock() - getAllocatedStock();
            if (availableStock < 0) {
                availableStock = 0;
            }
        }
        return availableStock;
    }

    /**
     * 获取是否缺货
     *
     * @return 是否缺货
     */
    @Transient
    public Boolean getIsOutOfStock() {
        return getStock() != null && getAllocatedStock() != null && getAllocatedStock() >= getStock();
    }

}
